#include <QtCore>
#include <QtNetwork>
#include <iostream>
#include <argp.h>
#include "grabber.h"

/* Some global stuff. */
const char *argp_program_version = APPNAME " from " __DATE__ " " __TIME__;
const char *argp_program_bug_address = "tv-grab-py-fi.googlecode.com";

/* Program documentation. */
static char doc[] = APPNAME " -- a program to grab EPG from m.telkku.com";

/* The options we understand. */
static struct argp_option options[] =
{
    {"quiet",        TvGrabber::keyQuiet,        0, 0, "Don't produce any output.", 0 },
    {"description",  TvGrabber::keyDescription,  0, 0, "Show the description line.", 0 },
    {"capabilities", TvGrabber::keyCapabilities, 0, 0, "Show capabilities information.", 0 },
    {"configure",    TvGrabber::keyConfigure,    0, 0, "Run configuration.", 0 },
    {"config-file",  TvGrabber::keyConfigFile,   "FILE", 0, "Use the specified config file.", 0 },
    {"output",       TvGrabber::keyOutput,       "FILE", 0, "Output to FILE instead of standard output.", 0 },
    {"days",         TvGrabber::keyDays,         "DAYS", 0, "Specify the number of days to grab.", 0 },
    {"offset",       TvGrabber::keyOffset,       "DAYS", 0, "Specify the number of days to add to current date to start grabbing.", 0 },
    { 0,0,0,0,0,0 }
};

/* Single option parser. */
static error_t parseOption( int key, char *arg, struct argp_state *state )
{
    /* Get the input argument from argp_parse, which we
       know is a pointer to our arguments structure. */
    TvGrabber *app = static_cast<TvGrabber *>( state->input );

    switch(key)
    {
    case TvGrabber::keyQuiet:
        app->setSilent(true);
        break;
    case TvGrabber::keyDescription:
    case TvGrabber::keyCapabilities:
    case TvGrabber::keyConfigure:
        app->setSuddenDeath(static_cast<TvGrabber::OptionKey>(key));
        break;
    case TvGrabber::keyConfigFile:
        app->setConfigFile(arg);
        break;
    case TvGrabber::keyOutput:
        app->setOutputFile(arg);
        break;
    case TvGrabber::keyDays:
        app->setDays( qMax( 0, qMin( MAX_DAYS, QString( arg ).toInt() ) ) );
        break;
    case TvGrabber::keyOffset:
        app->setOffset( qMax( 0, qMin( MAX_DAYS, QString( arg ).toInt() ) ) );
        break;
    default:
        return ARGP_ERR_UNKNOWN;
    }
    return 0;
}

/* Our argp parser. */
static struct argp argp = { options, parseOption, 0, doc, 0, 0, 0 };

//! CTOR
TvGrabber::TvGrabber(int argc, char **argv) :
    QCoreApplication( argc, argv ),
    qout(new QTextStream(stdout)),
    configFile("-"),
    suddenDeath(keyNone),
    silent(false),
    days(MAX_DAYS),
    offset(0),
    nam(new QNetworkAccessManager()),
    mainUrl("http://m.telkku.com")
{
    // Settings setup.
    setApplicationName(APPNAME);
    setOrganizationName("xmltv");
    settings = new QSettings();

    QTimer::singleShot(0, this, SLOT(deferredInit()));
}

//! DTOR
TvGrabber::~TvGrabber()
{
    delete qout;
}

//! Deferred init.
void TvGrabber::deferredInit()
{
    // Connect own signal to quit.
    connect(this, SIGNAL(aboutToQuit()), this, SLOT(quit()), Qt::QueuedConnection);

    // Connect NAM signals.
    connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(netAccessFinished(QNetworkReply*)));

    // Get the main URL.
    nam->get(QNetworkRequest(QUrl(mainUrl)))->setProperty("urlType", urlTypeMain);
}

//! Compress received data.
QString TvGrabber::compressResponse(QByteArray responseBytes)
{
    QStringList responseParts(QString(responseBytes).split("\n"));
    QString retVal;
    foreach(QString part, responseParts)
    {
        retVal += part.trimmed();
    }
    return retVal;
}

//! Main URL's network access finished.
void TvGrabber::mainUrlAccessFinished(QNetworkReply *reply)
{
    QString replyString(compressResponse(reply->readAll()));
    QRegExp rx("grouplink.+http://m\\.telkku\\.com/programtable/show/(\\d+)/(.+)\"", Qt::CaseInsensitive);
    rx.setMinimal(true);
    int pos=0;
    QString channelGroupBase("http://m.telkku.com/programtable/show/%1/%2");
    QNetworkRequest request;
    while((pos = rx.indexIn(replyString, pos)) != -1)
    {
        QString channelGroupNumber(rx.cap(1));
        QString dateString(rx.cap(2));
        qDebug() << "Channel group number:" << channelGroupNumber << ", date string:" << dateString;
        pos += rx.matchedLength();
        request.setUrl(QUrl(channelGroupBase.arg(channelGroupNumber, dateString)));
        nam->get(request)->setProperty("urlType", urlTypeChannelGroup);
    }
    qDebug() << "Done in mainUrlAccessFinished().";
}

//! Network access finished.
void TvGrabber::channelGroupAccesFinished(QNetworkReply *reply)
{
    qDebug() << "Response from:" << reply->url();
    QString replyString(compressResponse(reply->readAll()));
}

//! Network access finished.
void TvGrabber::netAccessFinished(QNetworkReply *reply)
{
    switch(reply->property("urlType").toInt())
    {
    case urlTypeMain:
        mainUrlAccessFinished(reply);
        break;
    case urlTypeChannelGroup:
        channelGroupAccesFinished(reply);
        break;
    default:
        break;
    }
    reply->deleteLater();
}

//! Reconfigure the channels.
void TvGrabber::reconfigure()
{
    settings->clear();
    qDebug() << "Cleared all settings.";
}

//by Wim Peeters: a console application
int main(int argc, char *argv[])
{
    TvGrabber app(argc, argv);

    /* Parse our arguments; every option seen by parseOption will
       be reflected in arguments. */
    argp_parse( &argp, argc, argv, 0, 0, qApp );

    // Run the app.
    int retVal = 0;
    switch( app.getSuddenDeath() )
    {
    case TvGrabber::keyCapabilities:
        app.cout() << "baseline" << endl << "manualconfig" << endl;
        break;
    case TvGrabber::keyDescription:
        app.cout() << "Suomi (m.telkku.com)" << endl;
        break;
    case TvGrabber::keyConfigure:
        app.reconfigure();
    default:
        qDebug() << "Running the app.";
        retVal = app.exec();
        break;
    }
    qDebug() << "All done, TTFN.";
    return retVal;
}
